#include "Containers/RangePair.h"
#include "File/BOSSOutputLoader.h"
#include "File/YamlLoader.h"
#include "Fit/RooFitBuilder.h"
#include "Functions/Draw.h"
#include "Globals/Settings.h"
#include "Particle/ReconstructedParticle.h"
#include "RooHistPdf.h"
#include "RooPlot.h"
#include "TCanvas.h"
#include <iostream>

using namespace BOSS_Afterburner;
using namespace BOSS_Afterburner::Detector::Units;
using namespace BOSS_Afterburner::Draw;
using namespace BOSS_Afterburner::Error;
using namespace BOSS_Afterburner::TerminalIO;
using namespace RooFit;
using namespace std;

void Sideband(const char* config_file)
{
  YamlLoader conf(config_file);

  BOSSOutputLoader data(conf["Input file"].as<string>().c_str());

  const auto& ranges = conf["Ranges"];
  RangePair   fit    = ranges["fit"];
  RangePair   plot   = ranges["plot"];

  ReconstructedParticle particle(conf["Reconstructed particle"]);

  const char* varname = Form("#it{M}_{%s}", particle.NameLaTeX());
  RooRealVar  var(varname, varname, plot.X1(), plot.X2(), GeVc2);

  RooFitBuilder builder(var);

  BranchPlotOptions fullshapeOpts(conf["Measurement signal"]);
  BranchPlotOptions sidebandOpts(conf["Data sideband plot"]);

  auto fullshapeHist = data.Draw(fullshapeOpts);
  auto sidebandHist  = data.Draw(sidebandOpts);

  RooDataHist fullshape("full shape", fullshapeHist->GetTitle(), var,
                        RooFit::Import(*fullshapeHist));
  RooDataHist sideband("sideband", sidebandHist->GetTitle(), var, RooFit::Import(*sidebandHist));

  auto frame = var.frame();
  fullshape.plotOn(frame, RooFit::LineWidth(2), RooFit::LineColor(kBlue + 2), RooFit::LineWidth(1),
                   RooFit::MarkerColor(kBlue + 2), RooFit::MarkerSize(.5));

  RooHistPdf sidebandPdf("sideband", "sideband", var, sideband, 0);

  // * Extract parameters from YAML * //
  const auto& variables = conf["Roofit variables"];
  if(!variables) return;
  const auto& varTrunc = variables["Truncated polynomial"];
  const auto& varArgus = variables["Argus"];
  const auto& varArBES = variables["Argus BESIII"];
  if(!varTrunc) return;
  if(!varArgus) return;

  auto ratio = builder.BuildVar(variables["Signal-to-background ratio"]);
  auto argus = builder.BuildArgus(varArgus);
  auto arBES = builder.BuildArgusBESIII(varArBES);
  auto trunc = builder.BuildTruncatedPolynomial(varTrunc);

  Color_t colour = kRed;
  sidebandPdf.fitTo(fullshape, RooFit::Range(fit.X1(), fit.X2()));
  sidebandPdf.plotOn(frame, RooFit::LineWidth(2), RooFit::LineColor(colour),
                     RooFit::Range(plot.X1(), plot.X2()));
  sidebandPdf.paramOn(frame, RooFit::Layout(.59, .92, .92), Format("NU"));

  // * Configure frame style * //
  if(frame)
  {
    frame->getAttText()->SetTextSize(.035);
    frame->getAttText()->SetTextColor(colour);
  }

  // * Write fitted histograms * //
  TCanvas c;
  c.SetBatch();
  frame->Draw();
  IndicateFitRange(conf);
  SaveCanvas(Form("Sideband_%s", particle.Name()), &c);
}

/// Main function that is called when executing the executable compiled using e.g. `g++`.
int main(int argc, char* argv[])
{
  CheckMainArguments(argc, argv, 1);
  Sideband(argv[1]);
  return 0;
}